"""
AIQuant Web降级数据提供器
当API不可用时提供降级数据，确保系统基本功能可用
"""

import logging
import random
from datetime import datetime, timedelta
from functools import wraps
from typing import Any, Callable, Dict, List, Optional

import pandas as pd

logger = logging.getLogger(__name__)


class FallbackDataProvider:
    """
    降级数据提供器
    
    提供以下功能：
    - 系统状态降级数据
    - 市场数据降级数据
    - 交易数据降级数据
    - 持仓数据降级数据
    - 策略数据降级数据
    """
    
    def __init__(self):
        """初始化降级数据提供器"""
        self.current_time = datetime.now()
        self.symbols = ['000001.SZ', '000002.SZ', '600000.SH', '600036.SH', '000858.SZ']
        self.strategies = ['量化选股策略', '市场中性策略', '统计套利策略', '趋势跟踪策略']
    
    def get_system_status(self) -> Dict[str, Any]:
        """获取系统状态降级数据"""
        return {
            'status': 'degraded',
            'message': '系统运行在降级模式',
            'timestamp': self.current_time.isoformat(),
            'services': {
                'api_server': {'status': 'offline', 'message': 'API服务不可用'},
                'database': {'status': 'unknown', 'message': '数据库连接状态未知'},
                'data_feed': {'status': 'offline', 'message': '数据源连接中断'},
                'trading_engine': {'status': 'offline', 'message': '交易引擎离线'}
            },
            'uptime': '0h 0m',
            'version': '1.0.0-fallback'
        }
    
    def get_system_health(self) -> Dict[str, Any]:
        """获取系统健康检查降级数据"""
        return {
            'overall_health': 'degraded',
            'checks': {
                'database_connection': False,
                'api_endpoints': False,
                'data_sources': False,
                'memory_usage': True,
                'disk_space': True
            },
            'metrics': {
                'cpu_usage': 0.0,
                'memory_usage': 0.0,
                'disk_usage': 0.0,
                'network_latency': 0.0
            },
            'last_check': self.current_time.isoformat()
        }
    
    def get_data_sources(self) -> List[Dict[str, Any]]:
        """获取数据源列表降级数据"""
        return [
            {
                'id': 'tushare',
                'name': 'Tushare数据源',
                'type': 'market_data',
                'status': 'offline',
                'last_update': (self.current_time - timedelta(hours=2)).isoformat(),
                'error_message': '连接超时'
            },
            {
                'id': 'wind',
                'name': 'Wind数据源',
                'type': 'market_data',
                'status': 'offline',
                'last_update': (self.current_time - timedelta(hours=1)).isoformat(),
                'error_message': '认证失败'
            },
            {
                'id': 'local_db',
                'name': '本地数据库',
                'type': 'storage',
                'status': 'unknown',
                'last_update': (self.current_time - timedelta(minutes=30)).isoformat(),
                'error_message': '连接状态未知'
            }
        ]
    
    def get_data_quality_metrics(self) -> Dict[str, Any]:
        """获取数据质量指标降级数据"""
        return {
            'overall_score': 0.0,
            'completeness': 0.0,
            'accuracy': 0.0,
            'timeliness': 0.0,
            'consistency': 0.0,
            'details': {
                'missing_data_points': 'N/A',
                'data_errors': 'N/A',
                'update_delay': 'N/A',
                'duplicate_records': 'N/A'
            },
            'last_check': self.current_time.isoformat()
        }
    
    def get_realtime_quotes(self, symbols: Optional[List[str]] = None) -> pd.DataFrame:
        """获取实时行情降级数据"""
        if symbols is None:
            symbols = self.symbols
        
        data = []
        for symbol in symbols:
            base_price = random.uniform(10, 100)
            data.append({
                'symbol': symbol,
                'name': f'股票{symbol[:6]}',
                'price': round(base_price, 2),
                'change': round(random.uniform(-2, 2), 2),
                'change_pct': round(random.uniform(-5, 5), 2),
                'volume': random.randint(1000000, 10000000),
                'turnover': round(random.uniform(100000000, 1000000000), 2),
                'high': round(base_price * random.uniform(1.0, 1.05), 2),
                'low': round(base_price * random.uniform(0.95, 1.0), 2),
                'open': round(base_price * random.uniform(0.98, 1.02), 2),
                'prev_close': round(base_price * random.uniform(0.98, 1.02), 2),
                'timestamp': self.current_time.isoformat()
            })
        
        return pd.DataFrame(data)
    
    def get_kline_data(self, symbol: str, period: str = '1d') -> pd.DataFrame:
        """获取K线数据降级数据"""
        periods = {'1m': 1440, '5m': 288, '15m': 96, '1h': 24, '1d': 30}
        count = periods.get(period, 30)
        
        data = []
        base_price = random.uniform(10, 100)
        current_price = base_price
        
        for i in range(count):
            # 生成随机价格变动
            change = random.uniform(-0.05, 0.05)
            current_price = max(current_price * (1 + change), 0.1)
            
            high = current_price * random.uniform(1.0, 1.02)
            low = current_price * random.uniform(0.98, 1.0)
            open_price = current_price * random.uniform(0.99, 1.01)
            close_price = current_price
            
            data.append({
                'symbol': symbol,
                'datetime': (self.current_time - timedelta(days=count-i)).isoformat(),
                'open': round(open_price, 2),
                'high': round(high, 2),
                'low': round(low, 2),
                'close': round(close_price, 2),
                'volume': random.randint(100000, 1000000),
                'turnover': round(random.uniform(10000000, 100000000), 2)
            })
        
        return pd.DataFrame(data)
    
    def get_active_orders(self) -> List[Dict[str, Any]]:
        """获取活跃订单降级数据"""
        orders = []
        for i in range(5):
            orders.append({
                'order_id': f'ORD{random.randint(100000, 999999)}',
                'symbol': random.choice(self.symbols),
                'side': random.choice(['buy', 'sell']),
                'order_type': random.choice(['limit', 'market']),
                'quantity': random.randint(100, 10000),
                'price': round(random.uniform(10, 100), 2),
                'filled_quantity': random.randint(0, 5000),
                'status': random.choice(['pending', 'partial_filled', 'submitted']),
                'create_time': (self.current_time - timedelta(minutes=random.randint(1, 60))).isoformat(),
                'update_time': (self.current_time - timedelta(minutes=random.randint(0, 30))).isoformat()
            })
        
        return orders
    
    def get_trade_history(self, limit: int = 20) -> List[Dict[str, Any]]:
        """获取交易历史降级数据"""
        trades = []
        for i in range(limit):
            trades.append({
                'trade_id': f'TRD{random.randint(100000, 999999)}',
                'order_id': f'ORD{random.randint(100000, 999999)}',
                'symbol': random.choice(self.symbols),
                'side': random.choice(['buy', 'sell']),
                'quantity': random.randint(100, 5000),
                'price': round(random.uniform(10, 100), 2),
                'amount': round(random.uniform(1000, 500000), 2),
                'commission': round(random.uniform(1, 50), 2),
                'trade_time': (self.current_time - timedelta(hours=random.randint(1, 72))).isoformat()
            })
        
        return trades
    
    def get_portfolio_positions(self) -> List[Dict[str, Any]]:
        """获取持仓信息降级数据"""
        positions = []
        for symbol in self.symbols:
            current_price = round(random.uniform(10, 100), 2)
            cost_price = round(current_price * random.uniform(0.9, 1.1), 2)
            quantity = random.randint(1000, 10000)
            
            positions.append({
                'symbol': symbol,
                'name': f'股票{symbol[:6]}',
                'quantity': quantity,
                'available_quantity': quantity - random.randint(0, 1000),
                'cost_price': cost_price,
                'current_price': current_price,
                'market_value': round(current_price * quantity, 2),
                'cost_value': round(cost_price * quantity, 2),
                'pnl': round((current_price - cost_price) * quantity, 2),
                'pnl_pct': round((current_price - cost_price) / cost_price * 100, 2),
                'weight': round(random.uniform(5, 25), 2),
                'last_update': self.current_time.isoformat()
            })
        
        return positions
    
    def get_portfolio_performance(self) -> Dict[str, Any]:
        """获取组合绩效降级数据"""
        return {
            'total_value': round(random.uniform(1000000, 10000000), 2),
            'total_cost': round(random.uniform(900000, 9000000), 2),
            'total_pnl': round(random.uniform(-100000, 1000000), 2),
            'total_pnl_pct': round(random.uniform(-10, 15), 2),
            'daily_pnl': round(random.uniform(-50000, 50000), 2),
            'daily_pnl_pct': round(random.uniform(-2, 2), 2),
            'max_drawdown': round(random.uniform(-15, -5), 2),
            'sharpe_ratio': round(random.uniform(0.5, 2.0), 2),
            'volatility': round(random.uniform(10, 30), 2),
            'last_update': self.current_time.isoformat()
        }
    
    def get_strategies(self) -> List[Dict[str, Any]]:
        """获取策略列表降级数据"""
        strategies = []
        for i, strategy_name in enumerate(self.strategies):
            strategies.append({
                'strategy_id': f'STRAT_{i+1:03d}',
                'name': strategy_name,
                'status': random.choice(['running', 'stopped', 'error']),
                'type': random.choice(['equity', 'futures', 'options']),
                'capital': round(random.uniform(1000000, 5000000), 2),
                'pnl': round(random.uniform(-100000, 200000), 2),
                'pnl_pct': round(random.uniform(-10, 20), 2),
                'max_drawdown': round(random.uniform(-15, -2), 2),
                'sharpe_ratio': round(random.uniform(0.5, 2.5), 2),
                'start_date': (self.current_time - timedelta(days=random.randint(30, 365))).date().isoformat(),
                'last_update': self.current_time.isoformat()
            })
        
        return strategies
    
    def get_strategy_performance(self, strategy_id: str) -> Dict[str, Any]:
        """获取策略绩效降级数据"""
        return {
            'strategy_id': strategy_id,
            'net_value': round(random.uniform(0.8, 1.5), 4),
            'total_return': round(random.uniform(-20, 50), 2),
            'annual_return': round(random.uniform(-10, 25), 2),
            'max_drawdown': round(random.uniform(-20, -2), 2),
            'sharpe_ratio': round(random.uniform(0.3, 2.5), 2),
            'calmar_ratio': round(random.uniform(0.2, 1.5), 2),
            'volatility': round(random.uniform(8, 35), 2),
            'win_rate': round(random.uniform(40, 70), 2),
            'profit_loss_ratio': round(random.uniform(1.0, 3.0), 2),
            'trade_count': random.randint(50, 500),
            'last_update': self.current_time.isoformat()
        }
    
    def get_risk_metrics(self) -> Dict[str, Any]:
        """获取风险指标降级数据"""
        return {
            'var_1d': round(random.uniform(-100000, -10000), 2),
            'var_5d': round(random.uniform(-200000, -20000), 2),
            'cvar_1d': round(random.uniform(-150000, -15000), 2),
            'cvar_5d': round(random.uniform(-300000, -30000), 2),
            'beta': round(random.uniform(0.5, 1.5), 2),
            'correlation_market': round(random.uniform(0.3, 0.9), 2),
            'tracking_error': round(random.uniform(2, 8), 2),
            'information_ratio': round(random.uniform(-1, 2), 2),
            'concentration_risk': round(random.uniform(10, 40), 2),
            'sector_exposure': {
                '金融': round(random.uniform(10, 30), 2),
                '科技': round(random.uniform(15, 35), 2),
                '消费': round(random.uniform(10, 25), 2),
                '医药': round(random.uniform(5, 20), 2),
                '其他': round(random.uniform(10, 30), 2)
            },
            'last_update': self.current_time.isoformat()
        }
    
    def get_risk_alerts(self) -> List[Dict[str, Any]]:
        """获取风险预警降级数据"""
        alerts = []
        alert_types = ['position_limit', 'drawdown', 'volatility', 'concentration']
        
        for i in range(random.randint(0, 3)):
            alerts.append({
                'alert_id': f'ALERT_{random.randint(1000, 9999)}',
                'type': random.choice(alert_types),
                'level': random.choice(['low', 'medium', 'high']),
                'message': '这是一个模拟风险预警',
                'symbol': random.choice(self.symbols) if random.random() > 0.5 else None,
                'value': round(random.uniform(0, 100), 2),
                'threshold': round(random.uniform(50, 150), 2),
                'create_time': (self.current_time - timedelta(minutes=random.randint(1, 120))).isoformat(),
                'status': random.choice(['active', 'acknowledged'])
            })
        
        return alerts
    
    def get_market_data(self, symbol: Optional[str] = None, data_type: str = 'quote') -> Dict[str, Any]:
        """获取市场数据降级数据"""
        if data_type == 'quote':
            if symbol:
                quotes_df = self.get_realtime_quotes([symbol])
                if not quotes_df.empty:
                    return quotes_df.iloc[0].to_dict()
            else:
                quotes_df = self.get_realtime_quotes()
                return {'quotes': quotes_df.to_dict('records')}
        elif data_type == 'kline':
            if symbol:
                kline_df = self.get_kline_data(symbol)
                return {'kline': kline_df.to_dict('records')}
        
        return {'error': '数据类型不支持', 'data_type': data_type}
    
    def get_trading_data(self, data_type: str = 'orders') -> Dict[str, Any]:
        """获取交易数据降级数据"""
        if data_type == 'orders':
            return {'orders': self.get_active_orders()}
        elif data_type == 'trades':
            return {'trades': self.get_trade_history()}
        elif data_type == 'positions':
            return {'positions': self.get_portfolio_positions()}
        elif data_type == 'performance':
            return self.get_portfolio_performance()
        
        return {'error': '数据类型不支持', 'data_type': data_type}
    
    def get_strategy_data(self, strategy_id: Optional[str] = None, data_type: str = 'list') -> Dict[str, Any]:
        """获取策略数据降级数据"""
        if data_type == 'list':
            return {'strategies': self.get_strategies()}
        elif data_type == 'performance' and strategy_id:
            return self.get_strategy_performance(strategy_id)
        elif data_type == 'risk':
            return self.get_risk_metrics()
        elif data_type == 'alerts':
            return {'alerts': self.get_risk_alerts()}
        
        return {'error': '数据类型不支持或缺少参数', 'data_type': data_type, 'strategy_id': strategy_id}
    
    def get_analysis_data(self, analysis_type: str = 'overview') -> Dict[str, Any]:
        """获取分析数据降级数据"""
        if analysis_type == 'overview':
            return {
                'portfolio_value': round(random.uniform(1000000, 10000000), 2),
                'daily_pnl': round(random.uniform(-50000, 50000), 2),
                'total_positions': len(self.symbols),
                'active_strategies': len(self.strategies),
                'risk_level': random.choice(['低', '中', '高']),
                'last_update': self.current_time.isoformat()
            }
        elif analysis_type == 'performance':
            return self.get_portfolio_performance()
        elif analysis_type == 'risk':
            return self.get_risk_metrics()
        
        return {'error': '分析类型不支持', 'analysis_type': analysis_type}
    
    def get_portfolio_data(self, data_type: str = 'overview') -> Dict[str, Any]:
        """获取组合数据降级数据"""
        if data_type == 'overview':
            return {
                'total_value': round(random.uniform(1000000, 10000000), 2),
                'available_cash': round(random.uniform(100000, 1000000), 2),
                'total_positions': len(self.symbols),
                'daily_pnl': round(random.uniform(-50000, 50000), 2),
                'total_pnl': round(random.uniform(-100000, 500000), 2),
                'last_update': self.current_time.isoformat()
            }
        elif data_type == 'positions':
            return {'positions': self.get_portfolio_positions()}
        elif data_type == 'performance':
            return self.get_portfolio_performance()
        
        return {'error': '数据类型不支持', 'data_type': data_type}
    
    def get_risk_data(self, data_type: str = 'metrics') -> Dict[str, Any]:
        """获取风险数据降级数据"""
        if data_type == 'metrics':
            return self.get_risk_metrics()
        elif data_type == 'alerts':
            return {'alerts': self.get_risk_alerts()}
        
        return {'error': '风险数据类型不支持', 'data_type': data_type}


# 全局降级数据提供器实例
_fallback_provider: Optional[FallbackDataProvider] = None


def get_fallback_provider() -> FallbackDataProvider:
    """
    获取全局降级数据提供器实例
    
    Returns:
        降级数据提供器实例
    """
    global _fallback_provider
    
    if _fallback_provider is None:
        _fallback_provider = FallbackDataProvider()
    
    return _fallback_provider


def with_fallback(fallback_method: str, show_warning: bool = True):
    """
    API调用降级装饰器
    
    Args:
        fallback_method: 降级方法名
        show_warning: 是否显示降级警告
        
    Returns:
        装饰器函数
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                # 尝试执行原函数
                return func(*args, **kwargs)
            except Exception as e:
                logger.warning(f"API调用失败，使用降级数据: {func.__name__} - {str(e)}")
                
                # 显示用户友好的警告信息
                if show_warning:
                    try:
                        import streamlit as st
                        st.warning(
                            f"⚠️ 数据服务暂时不可用，正在显示模拟数据。"
                            f"请稍后刷新页面或联系系统管理员。"
                        )
                    except ImportError:
                        pass
                
                # 使用降级数据
                fallback_provider = get_fallback_provider()
                fallback_func = getattr(fallback_provider, fallback_method, None)
                
                if fallback_func is None:
                    raise ValueError(f"降级方法不存在: {fallback_method}")
                
                # 调用降级方法
                return fallback_func(*args, **kwargs)
        
        return wrapper
    return decorator


if __name__ == "__main__":
    # 测试代码
    def test_fallback_provider():
        provider = FallbackDataProvider()
        
        # 测试系统状态
        status = provider.get_system_status()
        print(f"系统状态: {status}")
        
        # 测试实时行情
        quotes = provider.get_realtime_quotes()
        print(f"实时行情: {quotes}")
        
        # 测试持仓信息
        positions = provider.get_portfolio_positions()
        print(f"持仓信息: {positions}")
        
        # 测试装饰器
        @with_fallback('get_system_status', show_warning=False)
        def get_api_status():
            raise Exception("API不可用")
        
        result = get_api_status()
        print(f"降级结果: {result}")
    
    # 运行测试
    test_fallback_provider()